package com.kayb.patterns.creational;

import java.io.*;

/**
 * 原型模式
 * @author huangkaibin
 * @date 2018-08-28
 **/
public class Protype {

    // 浅复制，直接赋值
    static class Sheep implements Cloneable {
        private String name;
        public Sheep(String name) { this.name = name; }
        public void setName(String name) { this.name = name; }
        public String getName() { return name; }
        @Override
        public Sheep clone() throws CloneNotSupportedException {
            return new Sheep(name);
        }
    }

    /**
     * 浅复制
     * 1、 基本类型，如果变量是基本很类型，则拷贝其值，比如int、float等。
     * 2、 对象，如果变量是一个实例对象，则拷贝其地址引用，也就是说此时新对象与原来对象是公用该实例变量。
     * 3、 String字符串，若变量为String字符串，则拷贝其地址引用。但是在修改时，它会从字符串池中重新生成一个新的字符串，原有紫都城对象保持不变。
     */
    static class Sheep2 implements Cloneable {
        private String name;
        private Sheep sheep;
        public Sheep2(String name) { this.name = name; }
        public void setName(String name) { this.name = name; }
        public String getName() { return name; }
        @Override
        public Object clone() throws CloneNotSupportedException {
            return (Sheep2)super.clone();
        }
    }

    // 深度复制
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj){
        T cloneObj = null;
        try {
            //写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(obj);
            obs.close();

            //分配内存，写入原始对象，生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            //返回生成的新对象
            cloneObj = (T) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cloneObj;
    }

    static class Person implements Serializable{
        private static final long serialVersionUID = 1L;
        private String name;
        private Email email;

        public Person(String name, Email email) {
            this.name = name;
            this.email = email;
        }
    }
    static class Email implements Serializable{
        private static final long serialVersionUID = 1L;
        private String subject;

        public Email(String subject) {
            this.subject = subject;
        }
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep original = new Sheep("Jolly");
        System.out.println(original.getName()); // Jolly

        // 直接赋值
        Sheep cloned = original.clone();
        cloned.setName("Dolly");
        System.out.println(cloned.getName()); // Dolly

        // 浅复制
        Sheep2 sheep2 = new Sheep2("sheep2");
        sheep2.sheep = original;
        Sheep2 sheep21 = (Sheep2)sheep2.clone();
        System.out.println(sheep21.name);
        sheep21.name = "Kitty";
        System.out.println(sheep2.name);        // sheep2
        System.out.println(sheep21.name);       // Kitty
        System.out.println(sheep21.sheep.name); // Jolly

        // 深度复制
        Email email = new Email("请于今天12:30到1会议室参加会议...");
        Person person1 =  new Person("张三",email);

        Person person2 =  clone(person1);
        person2.name = ("李四");

        person1.email.subject = ("请于今天12:00到2会议室参加会议...");

        System.out.println(person1.name + "的邮件内容是：" + person1.email.subject);
        System.out.println(person2.name + "的邮件内容是：" + person2.email.subject);
    }

}
